﻿using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Linq;
namespace Athena.RemoteAddress.Implementations
{
    using ExceptionHandler;
    public class AddressResolver : IAddressResolver
    {
        private readonly IAddressModelSelector _addressModelSelector;
        private readonly IServiceAddressManager _serviceAddressManager;

        private readonly ConcurrentDictionary<string, AddressModelDescriptor> _addressModelDictionary;

        public AddressResolver(IAddressModelSelector addressModelSelector, IServiceAddressManager serviceAddressManager)
        {
            _addressModelSelector = addressModelSelector;
            _serviceAddressManager = serviceAddressManager;
            _addressModelDictionary = new ConcurrentDictionary<string, AddressModelDescriptor>();
        }

        public async Task<RemoteAddressModel> Resolver(string correlationId)
        {
            _addressModelDictionary.TryGetValue(correlationId, out AddressModelDescriptor addressModelDescriptor);
            if (addressModelDescriptor == null)
            {
                var serviceAddressList = await _serviceAddressManager.GetServiceAddressAsync();
                foreach (var serviceAddress in serviceAddressList)
                {
                    addressModelDescriptor = serviceAddress.AddressModelDescriptors.FirstOrDefault(x => x.Equals(correlationId));
                    if (addressModelDescriptor != null)
                    {
                        break;
                    }
                }
                if (addressModelDescriptor == null)
                {
                    throw new RpcException((int)AthenaRpcInvokeResultCodeDisplay.RpcCorrelationIdException, $"服务Id:{correlationId},解析服务地址失败。");
                }
                _addressModelDictionary.TryAdd(correlationId, addressModelDescriptor);
            }

            return await _addressModelSelector.SelectAsync(new AddressModelSelectContext()
            {
                AddressModelDescriptor = addressModelDescriptor
            });
        }

        public string BuildKeyNamespace(ServiceAddressDescriptor serviceAddressDescriptor, AddressModelDescriptor addressModelDescriptor)
        {
            return addressModelDescriptor.CorrelationId;
        }
    }
}
